package com.jctrip.hotel.source.service.dossen.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;

import javax.annotation.Resource;

import com.jctrip.hotel.common.util.RandomUtil;
import com.jctrip.hotel.domain.dao.HtSourceInfoDao;
import com.jctrip.hotel.domain.entity.HtSourceInfo;
import com.jctrip.hotel.source.service.HotelCommonTaskService;
import com.jctrip.hotel.source.service.dossen.DossenSigUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jctrip.hotel.common.constant.RedisKeyConstant;
import com.jctrip.hotel.common.enums.OrderStatusEnum;
import com.jctrip.hotel.common.enums.SourceEnum;
import com.jctrip.hotel.common.util.BeanUtil;
import com.jctrip.hotel.common.util.JsonUtil;
import com.jctrip.hotel.common.util.RedisUtil;
import com.jctrip.hotel.domain.entity.HtHotelStdInfo;
import com.jctrip.hotel.source.client.DossenClient;
import com.jctrip.hotel.source.model.OrderDataResult;
import com.jctrip.hotel.source.model.PriceCheckParam;
import com.jctrip.hotel.source.model.dossen.DossenAddOrderReq;
import com.jctrip.hotel.source.model.dossen.DossenCancelOrderReq;
import com.jctrip.hotel.source.model.dossen.DossenCheckPriceAndCountReq;
import com.jctrip.hotel.source.model.dossen.DossenCityData;
import com.jctrip.hotel.source.model.dossen.DossenGetHotelInfoReq;
import com.jctrip.hotel.source.model.dossen.DossenGetHotelRoomTypeReq;
import com.jctrip.hotel.source.model.dossen.DossenGetOrdersReq;
import com.jctrip.hotel.source.model.dossen.DossenGetPriceAndCountReq;
import com.jctrip.hotel.source.model.dossen.DossenHotelData;
import com.jctrip.hotel.source.model.dossen.DossenOrderData;
import com.jctrip.hotel.source.model.dossen.DossenPriceAndCountData;
import com.jctrip.hotel.source.model.dossen.DossenPriceAndCountData.ActivityResvRoomDTO;
import com.jctrip.hotel.source.model.dossen.DossenRatePlanData;
import com.jctrip.hotel.source.model.dossen.DossenResult;
import com.jctrip.hotel.source.model.dossen.DossenRoomTypeData;
import com.jctrip.hotel.source.model.dossen.DossenTokenData;
import com.jctrip.hotel.source.model.wehotel.req.OrderData;
import com.jctrip.hotel.source.service.basic.HtHotelStdInfoService;
import com.jctrip.hotel.source.service.dossen.DossenService;

import lombok.extern.slf4j.Slf4j;
import org.springframework.util.MultiValueMap;

/**
 * @Author henry
 * @Date 2023/6/6 21:43
 * @Description
 */
@Service
@Slf4j
public class DossenServiceImpl implements DossenService {

    @Resource
    private RedisUtil redisUtil;
    @Resource
    private DossenClient dossenClient;
    @Resource
    private HtHotelStdInfoService htHotelStdInfoService;
    @Resource
    private HtSourceInfoDao htSourceInfoDao;
    @Autowired
    private HotelCommonTaskService hotelCommonTaskService;

    @Override
    public String parseHotelId(String innId) {
        if (StringUtils.isBlank(innId)) {
            return null;
        }

        return innId.substring(SourceEnum.DOSSEN.getCode().length());
    }

    @Override
    public String parseInnId(String hotelId) {
        if (null == hotelId) {
            return null;
        }
        return SourceEnum.DOSSEN.getCode() + hotelId;
    }

    @Override
    public DossenTokenData token(String appId, String key) {
        DossenResult<String> dossenResult = dossenClient.token(appId, key);

        if (null == dossenResult) {
            return null;
        }

        if (1 != dossenResult.getCode()) {
            throw new RuntimeException(dossenResult.getMsg());
        }

        return JsonUtil.toObject(DossenTokenData.class, dossenResult.getData());
    }

    @Override
    public String tokenCache(String appId, String key) {
        String token = null;

        String tokenCacheKey = String.format("%s_%s", RedisKeyConstant.HOTEL_MAIN_DOSSEN_TOKEN_CACHE, appId);

        String lockKey = String.format("%s_%s", RedisKeyConstant.HOTEL_MAIN_DOSSEN_TOKEN_CACHE_LOCK, appId);
        long lockExpiry = 1 * 10;// 单位：秒

        for (int i = 0; i < 3; i++) {
            try {
                DossenTokenData dossenTokenData = (DossenTokenData) redisUtil.get(tokenCacheKey);
                // dossenTokenData非空 && dossenTokenData.getToken()非空 && dossenTokenData.getExpires()不过期
                if (null != dossenTokenData) {
                    token = dossenTokenData.getToken();
                    break;
                }

                if (redisUtil.setENx(lockKey, lockExpiry, lockKey)) {
                    dossenTokenData = token(appId, key);
                    redisUtil.set(tokenCacheKey, dossenTokenData);
                } else {
                    Thread.sleep(1 * 1000);
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        }

        return token;
    }

    @Override
    public List<DossenCityData> getCitiesList(String appId, String key) {
        List<DossenCityData> dossenCityDataList = new ArrayList<>();
        MultiValueMap<String, String> headers = getHeadersMap(appId, key);
        DossenResult<List<DossenCityData>> dossenResult = dossenClient.getCitiesList(headers, new HashMap());

        if (null == dossenResult) {
            return dossenCityDataList;
        }

        if (1 != dossenResult.getCode()) {
            throw new RuntimeException(dossenResult.getMsg() + "-" + dossenResult.getCode());
        }
        return dossenResult.getData();
    }

    @Override
    public Page<DossenHotelData> getHotelInfo(String appId, String key, DossenGetHotelInfoReq dossenGetHotelInfoReq) {
        Page<DossenHotelData> dossenHotelDataPage =
                new Page<>(dossenGetHotelInfoReq.getPageIndex(), dossenGetHotelInfoReq.getPageSize());

        MultiValueMap<String, String> headersMap = getHeadersMap(appId, key);
        DossenResult<List<DossenHotelData>> dossenResult = dossenClient.getHotelInfo(
                headersMap, dossenGetHotelInfoReq);

        if (null == dossenResult) {
            return dossenHotelDataPage;
        }

        if (1 != dossenResult.getCode()) {
            throw new RuntimeException(dossenResult.getMsg() + "-" + dossenResult.getCode());
        }

        List<DossenHotelData> dossenHotelDataList = dossenResult.getData();

        if (CollectionUtils.isEmpty(dossenHotelDataList)) {
            return dossenHotelDataPage;
        }

        // dossenHotelDataPage.setCurrent();
        dossenHotelDataPage.setSize(dossenResult.getPageSize());
        dossenHotelDataPage.setTotal(dossenResult.getTotalCount());
        dossenHotelDataPage.setRecords(dossenHotelDataList);

        return dossenHotelDataPage;
    }

    @Override
    public List<DossenRoomTypeData> getHotelRoomType(String appId, String key,
                                                     DossenGetHotelRoomTypeReq dossenGetHotelRoomTypeReq) {
        if (null == dossenGetHotelRoomTypeReq) {
            throw new RuntimeException("参数为空");
        }

        if (StringUtils.isBlank(dossenGetHotelRoomTypeReq.getHotelId())) {
            throw new RuntimeException("酒店ID为空");
        }

        List<DossenRoomTypeData> dossenRoomTypeDataList = new ArrayList<>();

        MultiValueMap<String, String> headersMap = getHeadersMap(appId, key);
        DossenResult<List<DossenRoomTypeData>> dossenResult =
                dossenClient.getHotelRoomType(headersMap, dossenGetHotelRoomTypeReq);

        if (null == dossenResult) {
            return dossenRoomTypeDataList;
        }

        if (1 != dossenResult.getCode()) {
            throw new RuntimeException(dossenResult.getMsg() + "-" + dossenResult.getCode());
        }
        dossenRoomTypeDataList = dossenResult.getData();

        return dossenRoomTypeDataList;
    }

    @Override
    public List<DossenPriceAndCountData> getPriceAndCount(String appId, String key,
                                                          DossenGetPriceAndCountReq dossenGetPriceAndCountReq) {
        if (null == dossenGetPriceAndCountReq) {
            throw new RuntimeException("参数为空");
        }

        if (StringUtils.isBlank(dossenGetPriceAndCountReq.getHotelId())) {
            throw new RuntimeException("酒店ID为空");
        }

        if (null == dossenGetPriceAndCountReq.getCheckInDay()) {
            throw new RuntimeException("入住时间为空");
        }

        if (null == dossenGetPriceAndCountReq.getCheckOutDay()) {
            throw new RuntimeException("离店时间为空");
        }

        List<DossenPriceAndCountData> dossenPriceAndCountDataList = new ArrayList<>();

        MultiValueMap<String, String> headersMap = getHeadersMap(appId, key);
        DossenResult<List<DossenPriceAndCountData>> dossenResult =
                dossenClient.getPriceAndCount(headersMap, dossenGetPriceAndCountReq);

        if (null == dossenResult) {
            return dossenPriceAndCountDataList;
        }

        if (1 != dossenResult.getCode()) {
            throw new RuntimeException(dossenResult.getMsg() + "-" + dossenResult.getCode());
        }
        dossenPriceAndCountDataList = dossenResult.getData();
        return dossenPriceAndCountDataList;
    }

    @Override
    public List<DossenRatePlanData> getECRateplan(String appId, String key) {
        List<DossenRatePlanData> dossenRatePlanDataList = new ArrayList<>();

        MultiValueMap<String, String> headersMap = getHeadersMap(appId, key);
        DossenResult<List<DossenRatePlanData>> dossenResult = dossenClient.getECRateplan(
                headersMap, new HashMap<>());

        if (null == dossenResult) {
            return dossenRatePlanDataList;
        }

        if (1 != dossenResult.getCode()) {
            throw new RuntimeException(dossenResult.getMsg() + "-" + dossenResult.getCode());
        }

        dossenRatePlanDataList = dossenResult.getData();

        return dossenRatePlanDataList;
    }

    @Override
    public Integer getBreakfastCount(String appId, String key, String hotelId, String activityCode) {
        Integer breakfastCount = null;
        HtHotelStdInfo hotelInfoData = htHotelStdInfoService.getOne(
                new LambdaQueryWrapper<HtHotelStdInfo>().eq(HtHotelStdInfo::getHotelId, parseInnId(hotelId)));

        // hotelInfoData.getRestaurant() 1、有餐厅 0 无餐厅
        if (null == hotelInfoData || null == hotelInfoData.getSupportRestaurant()
                || 0 == hotelInfoData.getSupportRestaurant()) {
            breakfastCount = 0;
        } else {
            if (StringUtils.isBlank(activityCode)) {
                // todo
                breakfastCount = 2;
            } else {
                String rpCacheKey =
                        String.format("%s_%s_%s", RedisKeyConstant.HOTEL_MAIN_DOSSEN_RP_CACHE, appId, activityCode);
                String rpCacheLockKey =
                        String.format("%s_%s_%s", RedisKeyConstant.HOTEL_MAIN_DOSSEN_RP_CACHE_LOCK, appId,
                                activityCode);
                long rpCacheLockExpiry = 1 * 10;// 单位：秒

                for (int i = 0; i < 3; i++) {
                    try {
                        DossenRatePlanData dossenRatePlanData = (DossenRatePlanData) redisUtil.get(rpCacheKey);
                        if (null != dossenRatePlanData) {
                            breakfastCount = dossenRatePlanData.getBreakfastCount();
                            break;
                        }

                        if (redisUtil.setENx(rpCacheLockKey, rpCacheLockExpiry, rpCacheLockKey)) {
                            List<DossenRatePlanData> dossenRatePlanDataList = getECRateplan(appId, key);
                            dossenRatePlanData = dossenRatePlanDataList.stream()
                                    .filter(o -> o.getActivityCode().equals(activityCode)).findAny().orElse(null);
                            redisUtil.set(rpCacheKey, dossenRatePlanData);
                        } else {
                            Thread.sleep(1 * 1000);
                        }
                    } catch (Exception e) {
                        log.error(e.getMessage(), e);
                    }
                }
            }
        }

        return breakfastCount;
    }


    @Override
    public List<DossenPriceAndCountData> checkPriceAndCount(String appId, String key,
                                                            DossenCheckPriceAndCountReq dossenCheckPriceAndCountReq) {
        if (null == dossenCheckPriceAndCountReq) {
            throw new RuntimeException("参数为空");
        }

        if (StringUtils.isBlank(dossenCheckPriceAndCountReq.getHotelId())) {
            throw new RuntimeException("酒店ID为空");
        }

        if (StringUtils.isBlank(dossenCheckPriceAndCountReq.getRoomTypeId())) {
            throw new RuntimeException("房型ID为空");
        }

        if (null == dossenCheckPriceAndCountReq.getCheckInDate()) {
            throw new RuntimeException("入住时间为空");
        }

        if (null == dossenCheckPriceAndCountReq.getCheckOutDate()) {
            throw new RuntimeException("离店时间为空");
        }

        if (null == dossenCheckPriceAndCountReq.getNum()) {
            throw new RuntimeException("预订间数为空");
        }

        List<DossenPriceAndCountData> dossenPriceAndCountDataList = new ArrayList<>();

        MultiValueMap<String, String> headersMap = getHeadersMap(appId, key);
        DossenResult<List<DossenPriceAndCountData>> dossenResult =
                dossenClient.checkPriceAndCount(headersMap, dossenCheckPriceAndCountReq);

        if (null == dossenResult) {
            return dossenPriceAndCountDataList;
        }

        if (1 != dossenResult.getCode() && 10000 != dossenResult.getCode()) {
            throw new RuntimeException(dossenResult.getMsg() + "-" + dossenResult.getCode());
        }

        dossenPriceAndCountDataList = dossenResult.getData();

        return dossenPriceAndCountDataList;
    }


    @Override
    public OrderDataResult postOrder(String appId, String key,
                                     DossenAddOrderReq dossenAddOrderReq, PriceCheckParam priceCheck) {
        if (null == dossenAddOrderReq) {
            throw new RuntimeException("参数为空");
        }

        if (StringUtils.isBlank(dossenAddOrderReq.getHotelId())) {
            throw new RuntimeException("酒店ID为空");
        }

        if (StringUtils.isBlank(dossenAddOrderReq.getRoomTypeId())) {
            throw new RuntimeException("房型ID为空");
        }

        if (null == dossenAddOrderReq.getCheckInDate()) {
            throw new RuntimeException("入住时间为空");
        }

        if (null == dossenAddOrderReq.getCheckOutDate()) {
            throw new RuntimeException("离店时间为空");
        }

        if (null == dossenAddOrderReq.getNum()) {
            throw new RuntimeException("预订间数为空");
        }

        // todo

        String remark =
                "房费由嘉程商旅支付，无需向客人收取，发票请勿开给住店客人，由东呈大客户部统一联系各门店按月度收取，客人如有异议请让其联系预订渠道";
        dossenAddOrderReq.setRemark(remark);

        // 获取实时房价
        DossenCheckPriceAndCountReq checkPriceAndCountReq = new DossenCheckPriceAndCountReq();
        checkPriceAndCountReq.setHotelId(dossenAddOrderReq.getHotelId());
        checkPriceAndCountReq.setRoomTypeId(dossenAddOrderReq.getRoomTypeId());
        checkPriceAndCountReq.setCheckInDate(dossenAddOrderReq.getCheckInDate());
        checkPriceAndCountReq.setCheckOutDate(dossenAddOrderReq.getCheckOutDate());
        checkPriceAndCountReq.setActivityCode(dossenAddOrderReq.getActivityCode());
        checkPriceAndCountReq.setNum(dossenAddOrderReq.getNum());
        checkPriceAndCountReq.setEnterpriseProtocolCode(dossenAddOrderReq.getEnterpriseProtocolCode());

        List<DossenPriceAndCountData> dossenPriceAndCountData = checkPriceAndCount(appId, key, checkPriceAndCountReq);
        BigDecimal totalAdvanceRate = new BigDecimal(0);
        BigDecimal raisedTotalPrice = BigDecimal.valueOf(0);
        for (DossenPriceAndCountData priceAndCountData : Optional.of(dossenPriceAndCountData)
                .orElseThrow(() -> new RuntimeException("获取房态信息失败"))) {
            ActivityResvRoomDTO activityResvRoomDTO = new ActivityResvRoomDTO();

            if (StringUtils.isBlank(dossenAddOrderReq.getActivityCode())) {
                BeanUtil.copyProperties(priceAndCountData, activityResvRoomDTO);
            } else {
                activityResvRoomDTO =
                        Optional.ofNullable(priceAndCountData.getActivityResvRoomList()).orElse(new ArrayList<>())
                                .stream()
                                .filter(dto -> StringUtils.isNotBlank(dossenAddOrderReq.getActivityCode())
                                        && dossenAddOrderReq.getActivityCode().equals(dto.getActivityCode()))
                                .findFirst()
                                .get();
                if (activityResvRoomDTO == null) {
                    BeanUtil.copyProperties(priceAndCountData, activityResvRoomDTO);
                }
            }
            BigDecimal advanceRate = activityResvRoomDTO.getRoomPrice();
            totalAdvanceRate = totalAdvanceRate.add(advanceRate);
            raisedTotalPrice = raisedTotalPrice.add(priceCheck.getRaiseFunc().apply(advanceRate));

        }
        // todo 临时价格不还原
//        if (priceCheck.getTotalRate().compareTo(raisedTotalPrice.multiply(BigDecimal.valueOf(dossenAddOrderReq.getNum()))
//                .subtract(priceCheck.getTolerancePrice())) < 0) {
//            log.error("订单销售价不能低于采购总价，订单销售价={}，采购总价={}, 容差金额={}",
//                    priceCheck.getTotalRate(), raisedTotalPrice, priceCheck.getTolerancePrice());
//            throw new RuntimeException("订单销售价不能低于采购总价");
//        }
        if (priceCheck.getTotalRate().compareTo(totalAdvanceRate.multiply(BigDecimal.valueOf(dossenAddOrderReq.getNum()))
                .subtract(priceCheck.getTolerancePrice())) < 0) {
            String error = String.format("订单销售价不能低于采购总价，订单销售价=%s，采购总价=%s, 容差金额=%s, 目前差额=%s",
                    priceCheck.getTotalRate(),
                    totalAdvanceRate.multiply(BigDecimal.valueOf(dossenAddOrderReq.getNum())),
                    priceCheck.getTolerancePrice(),
                    totalAdvanceRate.multiply(BigDecimal.valueOf(dossenAddOrderReq.getNum())).subtract(priceCheck.getTotalRate()));
            hotelCommonTaskService.insertOrderErrorLog(dossenAddOrderReq.getOutOrderId(),
                    JsonUtil.toString(dossenAddOrderReq), error);
            log.error("订单销售价不能低于采购总价，订单销售价={}，采购总价={}, 容差金额={}, 目前差额={}",
                    priceCheck.getTotalRate(), totalAdvanceRate.multiply(BigDecimal.valueOf(dossenAddOrderReq.getNum())),
                    priceCheck.getTolerancePrice(), totalAdvanceRate.multiply(BigDecimal.valueOf(dossenAddOrderReq.getNum())).subtract(priceCheck.getTotalRate()));
            throw new RuntimeException("订单销售价不能低于采购总价");
        }
        MultiValueMap<String, String> headersMap = getHeadersMap(appId, key);
        dossenAddOrderReq.setSumPrice(totalAdvanceRate.multiply(BigDecimal.valueOf(dossenAddOrderReq.getNum())).intValue());
        DossenResult<String> dossenResult = dossenClient.addOrder(headersMap, dossenAddOrderReq);

        if (null == dossenResult) {
            return null;
        }

        if (1 != dossenResult.getCode()) {
            hotelCommonTaskService.insertOrderErrorLog(dossenAddOrderReq.getOutOrderId(),
                    JsonUtil.toString(dossenAddOrderReq), dossenResult.getMsg());
            throw new RuntimeException(dossenResult.getMsg());
        }
        return OrderDataResult.builder().orderCode(dossenResult.getData()).externalId(dossenAddOrderReq.getOutOrderId())
                .totalRate(totalAdvanceRate.multiply(BigDecimal.valueOf(dossenAddOrderReq.getNum()))).orderState(
                        OrderStatusEnum.BOOK_SUCCESS.getCode()).requestJsonStr(JsonUtil.toString(dossenAddOrderReq))
                .responseJsonStr(JsonUtil.toString(dossenResult)).build();
    }

    /**
     * 无容差
     *
     * @param appId
     * @param key
     * @param dossenAddOrderReq
     * @return
     */
    @Override
    public OrderDataResult postOrder(String appId, String key, DossenAddOrderReq dossenAddOrderReq) {
        if (null == dossenAddOrderReq) {
            throw new RuntimeException("参数为空");
        }

        if (StringUtils.isBlank(dossenAddOrderReq.getHotelId())) {
            throw new RuntimeException("酒店ID为空");
        }

        if (StringUtils.isBlank(dossenAddOrderReq.getRoomTypeId())) {
            throw new RuntimeException("房型ID为空");
        }

        if (null == dossenAddOrderReq.getCheckInDate()) {
            throw new RuntimeException("入住时间为空");
        }

        if (null == dossenAddOrderReq.getCheckOutDate()) {
            throw new RuntimeException("离店时间为空");
        }

        if (null == dossenAddOrderReq.getNum()) {
            throw new RuntimeException("预订间数为空");
        }
        // todo
        String remark =
                "房费由嘉程商旅支付，无需向客人收取，发票请勿开给住店客人，由东呈大客户部统一联系各门店按月度收取，客人如有异议请让其联系预订渠道";
        dossenAddOrderReq.setRemark(remark);

        String resvId = null;

        // 获取实时房价
        DossenCheckPriceAndCountReq checkPriceAndCountReq = new DossenCheckPriceAndCountReq();
        checkPriceAndCountReq.setHotelId(dossenAddOrderReq.getHotelId());
        checkPriceAndCountReq.setRoomTypeId(dossenAddOrderReq.getRoomTypeId());
        // todo
        checkPriceAndCountReq.setCheckInDate(dossenAddOrderReq.getCheckInDate());
        checkPriceAndCountReq.setCheckOutDate(dossenAddOrderReq.getCheckOutDate());
//        checkPriceAndCountReq.setIsShowTimeLimitActivity(dossenAddOrderReq.getIsShowTimeLimitActivity());
        // todo
        // String activityCode = postOrder.getProductCode();
        checkPriceAndCountReq.setActivityCode(dossenAddOrderReq.getActivityCode());
        checkPriceAndCountReq.setNum(dossenAddOrderReq.getNum());
        checkPriceAndCountReq.setEnterpriseProtocolCode(dossenAddOrderReq.getEnterpriseProtocolCode());

        List<DossenPriceAndCountData> dossenPriceAndCountData = checkPriceAndCount(appId, key, checkPriceAndCountReq);
        BigDecimal totalAdvanceRate = new BigDecimal(0);
        for (DossenPriceAndCountData priceAndCountData : Optional.of(dossenPriceAndCountData)
                .orElseThrow(() -> new RuntimeException("获取房态信息失败"))) {
            ActivityResvRoomDTO activityResvRoomDTO = new ActivityResvRoomDTO();
            if (StringUtils.isBlank(dossenAddOrderReq.getActivityCode())) {
                BeanUtil.copyProperties(priceAndCountData, activityResvRoomDTO);
            } else {
                activityResvRoomDTO =
                        Optional.ofNullable(priceAndCountData.getActivityResvRoomList()).orElse(new ArrayList<>())
                                .stream()
                                .filter(dto -> StringUtils.isNotBlank(dossenAddOrderReq.getActivityCode())
                                        && dossenAddOrderReq.getActivityCode().equals(dto.getActivityCode()))
                                .findFirst()
                                .get();
                if (activityResvRoomDTO == null) {
                    BeanUtil.copyProperties(priceAndCountData, activityResvRoomDTO);
                }
            }
            BigDecimal advanceRate = activityResvRoomDTO.getRoomPrice();
            totalAdvanceRate = totalAdvanceRate.add(advanceRate);
        }
        dossenAddOrderReq.setSumPrice(totalAdvanceRate.multiply(BigDecimal.valueOf(dossenAddOrderReq.getNum())).intValue());

        MultiValueMap<String, String> headersMap = getHeadersMap(appId, key);
        DossenResult<String> dossenResult = dossenClient.addOrder(headersMap, dossenAddOrderReq);
        if (null == dossenResult) {
            return null;
        }

        if (1 != dossenResult.getCode()) {
            throw new RuntimeException(dossenResult.getMsg() + "-" + dossenResult.getCode());
        }
        return OrderDataResult.builder().orderCode(dossenResult.getData()).externalId(dossenAddOrderReq.getOutOrderId())
                .totalRate(totalAdvanceRate.multiply(BigDecimal.valueOf(dossenAddOrderReq.getNum()))).orderState(
                        OrderStatusEnum.BOOK_SUCCESS.getCode()).requestJsonStr(JsonUtil.toString(dossenAddOrderReq))
                .responseJsonStr(JsonUtil.toString(dossenResult)).build();
    }

    @Override
    public OrderData queryOrderData(String appId, String key, String orderNo, String outOrderNo) {
        DossenGetOrdersReq req = DossenGetOrdersReq.builder()
                .outOrderId(outOrderNo)
                .resvId(orderNo)
                .pageSize(10)  //必填默认
                .pageIndex(1)  //必填默认
                .build();
        DossenOrderData order = getOrder(appId, key, req);
        OrderData result = new OrderData();
        result.setOrderCode(orderNo);
        result.setExternalId(outOrderNo);
        Integer orderState = null;
        if (StringUtils.isNotBlank(order.getOrderStatus())) {
            switch (order.getOrderStatus()) {
                case "R":
                    orderState = 1;
                    break;
                case "O":
                    orderState = 4;
                    break;
                case "X":
                    orderState = 2;
                    break;
                case "N":
                    orderState = 3;
                    break;
                case "CO":
                    orderState = 5;
                    break;
                default:
            }
        }
        result.setOrderState(orderState);
        return result;
    }

    @Override
    public DossenOrderData getOrder(String appId, String key, DossenGetOrdersReq dossenGetOrdersReq) {
        if (null == dossenGetOrdersReq) {
            throw new RuntimeException("参数为空");
        }

        if (StringUtils.isBlank(dossenGetOrdersReq.getOutOrderId())) {
            throw new RuntimeException("外部订单号为空");
        }

        DossenOrderData dossenOrderData = null;

        MultiValueMap<String, String> headersMap = getHeadersMap(appId, key);
        DossenResult<List<DossenOrderData>> dossenResult = dossenClient.getOrders(headersMap, dossenGetOrdersReq);

        if (null == dossenResult) {
            return dossenOrderData;
        }

        if (1 != dossenResult.getCode()) {
            throw new RuntimeException(dossenResult.getMsg() + "-" + dossenResult.getCode());
        }

        if (CollectionUtils.isNotEmpty(dossenResult.getData())) {
            dossenOrderData = dossenResult.getData().get(0);
        }

        return dossenOrderData;
    }

    @Override
    public DossenOrderData getDirectOrder(String sourceId, DossenGetOrdersReq dossenGetOrdersReq) {
        if (null == dossenGetOrdersReq) {
            throw new RuntimeException("参数为空");
        }

        if (StringUtils.isBlank(dossenGetOrdersReq.getOutOrderId())) {
            throw new RuntimeException("外部订单号为空");
        }
        HtSourceInfo htSourceInfo =
                htSourceInfoDao.selectOne(new LambdaQueryWrapper<HtSourceInfo>().eq(HtSourceInfo::getSourceId,
                        sourceId));
        if (htSourceInfo == null) {
            throw new RuntimeException("供应商账户为空");
        }
        String appId = htSourceInfo.getSourceAppId();
        String key = htSourceInfo.getSourceSecret();

        DossenOrderData dossenOrderData = null;

        MultiValueMap<String, String> headersMap = getHeadersMap(appId, key);
        DossenResult<List<DossenOrderData>> dossenResult = dossenClient.getOrders(headersMap, dossenGetOrdersReq);

        if (null == dossenResult) {
            throw new RuntimeException("返回订单信息为空");
        }

        if (1 != dossenResult.getCode()) {
            throw new RuntimeException(dossenResult.getMsg());
        }

        if (CollectionUtils.isNotEmpty(dossenResult.getData())) {
            dossenOrderData = dossenResult.getData().get(0);
        }

        return dossenOrderData;
    }

    @Override
    public void cancelOrder(String appId, String key, DossenCancelOrderReq dossenCancelOrderReq) {
        if (null == dossenCancelOrderReq) {
            throw new RuntimeException("参数为空");
        }

        if (StringUtils.isBlank(dossenCancelOrderReq.getResvId())) {
            throw new RuntimeException("东呈订单号为空");
        }

        MultiValueMap<String, String> headersMap = getHeadersMap(appId, key);
        DossenResult dossenResult = dossenClient.cancelOrder(headersMap, dossenCancelOrderReq);

        if (null == dossenResult) {
            return;
        }

        if (1 != dossenResult.getCode()) {
            throw new RuntimeException(dossenResult.getMsg() + "-" + dossenResult.getCode());
        }

        return;
    }

    public MultiValueMap<String, String> getHeadersMap(String appId, String key) {
        try {
            while (key.length() % 16 != 0) {
                key += "\0";
            }
            String nonce = RandomUtil.createRandomStr(8);
            String timestamp = String.valueOf(System.currentTimeMillis());
            String txt = appId + nonce + timestamp;
            DossenSigUtils util = new DossenSigUtils(key); // 密钥
            String sign = util.encryptData(txt);
            MultiValueMap<String, String> headers = new HttpHeaders();
            headers.add("App-Id", appId);
            headers.add("Nonce", nonce);
            headers.add("Timestamp", timestamp);
            headers.add("Signature", sign);
            return headers;
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return new HttpHeaders();
    }
}
